package net.aetherial.context.grounding.estimators;

import java.util.*;

import net.aetherial.context.grounding.estimators.loggers.RegressionLogger;

/**
 * Applies a simple linear model (often learned by the regression learner) to weight estimates provide by child estimators.
 */

public class LinearModelEstimator extends Estimator
{
	private RegressionLogger regLogger;
	
	private ArrayList<Double> predictedValues;
	private ArrayList<Double> codedValues;
	
	private HashMap<Estimator, Double> estimators;
	private double intercept;
	
	/**
	 * @see net.aetherial.context.grounding.estimators.Estimator#reset()
	 */
	
	public void reset ()
	{
		super.reset ();

		predictedValues = new ArrayList<Double> ();
		codedValues = new ArrayList<Double> ();
		regLogger.reset ();
		
		for (Estimator e: estimators.keySet ())
			e.reset ();
	}

	/**
	 * Constructor.
	 */
	
	public LinearModelEstimator ()
	{
		super ();
		
		predictedValues = new ArrayList<Double> ();
		codedValues = new ArrayList<Double> ();

		regLogger = new RegressionLogger ();
		
		estimators = new HashMap<Estimator, Double> ();
	}

	/**
	 * Adds an estimator with the default weight/coefficient of 1.0 to the aggregate learner.
	 * 
	 * @param e		New child estimator.
	 */
	
	public void addEstimator (Estimator e)
	{
		this.addEstimatorWithCoefficient (e, 1.0);
	}

	/**
	 * Adds an estimator with the specified weight/coefficient to the aggregate learner.
	 * 
	 * @param e		New child estimator
	 * @param d		Weight/coefficient of the new estimator's contribution to the linear model.
	 */
	
	public void addEstimatorWithCoefficient(Estimator e, double d) 
	{
		estimators.put (e, d);
	}

	/**
	 * Sets the intercept of the linear equation.
	 * 
	 * @param i		Intercept.
	 */
	
	public void setIntercept (double i)
	{
		intercept = i;
	}
	
	/**
	 * @see net.aetherial.context.grounding.estimators.Estimator#estimate(java.util.Map)
	 */
	
	public double estimate (Map<String, Map<String, Object>> layers) 
	{
		double score = super.estimate (layers);
		
		codedValues.add (score);
		
		double finalScore = intercept;
		
		for (Estimator e: estimators.keySet ())
			finalScore += (estimators.get (e)) * e.estimate (layers);

		predictedValues.add (finalScore);
			
		regLogger.log (codedValues, predictedValues);

		return finalScore;
	}

	/**
	 * Returns "LinearModelEstimator".
	 * 
	 * @see net.aetherial.context.grounding.estimators.Estimator#getName()
	 */
	
	public String getName() 
	{
		return "LinearModelEstimator";
	}

	/**
	 * @see net.aetherial.context.grounding.estimators.Estimator#estimate(java.lang.String, java.lang.String, double)
	 */
	
	public double estimate (String sender, String contribution, double score) 
	{
		return score;
	}

}
